/**************************************************************************//**
 * @file     hal_stm32f1xx_gpio_api.h
 * @brief    stm32f1xx GPIO模块对外提供的公共接口
 * @version  V0.0.1
 * @date     2020-02-01
 ******************************************************************************/
/*
 * Copyright (c) 2004, 2005 by xiao xiang. All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software
 * is freely granted, provided that this notice is preserved.
 */
#ifndef _HAL_STM32F1XX_GPIO_API_H_
#define _HAL_STM32F1XX_GPIO_API_H_

#include "common.h"
#include "hal_stm32f1xx_reg_base_api.h"

/*
 * 复位期间和刚复位后，复用功能未开启， I/O端口被配置成浮空输入模式(CNFx[1:0]=01b，MODEx[1:0]=00b)。
 * 复位后， JTAG引脚被置于输入上拉或下拉模式：
 * ─ PA15： JTDI置于上拉模式
 * ─ PA14： JTCK置于下拉模式
 * ─ PA13： JTMS置于上拉模式
 * ─ PB4： JNTRST置于上拉模式
*/ 

// 复用功能(AF)
// 使用默认复用功能前必须对端口位配置寄存器编程。
// ● 对于复用的输入功能，端口必须配置成输入模式(浮空、上拉或下拉)且输入引脚必须由外部驱动
// ● 对于复用输出功能，端口必须配置成复用功能输出模式(推挽或开漏)。
// ● 对于双向复用功能，端口位必须配置复用功能输出模式(推挽或开漏)。这时，输入驱动器被配置成浮空输入模式。
// 如果把端口配置成复用输出功能，则引脚和输出寄存器断开，并和片上外设的输出信号连接。
// 如果软件把一个GPIO脚配置成复用输出功能，但是外设没有被激活，它的输出将不确定。

/* 引脚定义，用于BSRR和BRR寄存器设置引脚为0或1 */
#define P0  ((U16)BIT(0))
#define P1  ((U16)BIT(1))
#define P2  ((U16)BIT(2))
#define P3  ((U16)BIT(3))
#define P4  ((U16)BIT(4))
#define P5  ((U16)BIT(5))
#define P6  ((U16)BIT(6))
#define P7  ((U16)BIT(7))
#define P8  ((U16)BIT(8))
#define P9  ((U16)BIT(9))
#define P10 ((U16)BIT(10))
#define P11 ((U16)BIT(11))
#define P12 ((U16)BIT(12))
#define P13 ((U16)BIT(13))
#define P14 ((U16)BIT(14))
#define P15 ((U16)BIT(15))

/** 
  * @brief 端口配置低寄存器(GPIOx_CRL) (x=A..E)
  * @note 偏移地址： 0x00  复位值： 0x4444 4444
  */
typedef union {
    struct {
        __IOM uint32_t MODE0 :2;  /*!< Portx，端口0， 00=输入（复位后状态） 01=输出最大10MHz 02=输出最大2MHz 02=输出最大50MHz */
        __IOM uint32_t CNF0  :2;  /*!< Portx，端口0， 为输入时：00=模拟输入 01=浮空输入 10=上拉/下拉输入 11=保留
                                                     为输出时，00=推挽输出 01=开漏输出 10=复用功能推挽输出  11=复用功能开漏输出 */
        __IOM uint32_t MODE1 :2;  /*!< Portx，端口1 */
        __IOM uint32_t CNF1  :2;  /*!< Portx，端口1 */
        __IOM uint32_t MODE2 :2;  /*!< Portx，端口2 */
        __IOM uint32_t CNF2  :2;  /*!< Portx，端口2 */
        __IOM uint32_t MODE3 :2;  /*!< Portx，端口3 */
        __IOM uint32_t CNF3  :2;  /*!< Portx，端口3 */
        __IOM uint32_t MODE4 :2;  /*!< Portx，端口4 */
        __IOM uint32_t CNF4  :2;  /*!< Portx，端口4 */
        __IOM uint32_t MODE5 :2;  /*!< Portx，端口5 */
        __IOM uint32_t CNF5  :2;  /*!< Portx，端口5 */
        __IOM uint32_t MODE6 :2;  /*!< Portx，端口6 */
        __IOM uint32_t CNF6  :2;  /*!< Portx，端口6 */
        __IOM uint32_t MODE7 :2;  /*!< Portx，端口7 */
        __IOM uint32_t CNF7  :2;  /*!< Portx，端口7 */
    };
    __IOM uint32_t reg;
}UN_GPIO_CRL;

/** 
  * @brief 端口配置低寄存器(GPIOx_CRL) (x=A..E)
  * @note 偏移地址： 0x00  复位值： 0x4444 4444
  */
typedef union {
    struct {
        __IOM uint32_t MODE8  :2;  /*!< Portx，端口8 */
        __IOM uint32_t CNF8   :2;  /*!< Portx，端口8 */
        __IOM uint32_t MODE9  :2;  /*!< Portx，端口9 */
        __IOM uint32_t CNF9   :2;  /*!< Portx，端口9 */
        __IOM uint32_t MODE10 :2;  /*!< Portx，端口10 */
        __IOM uint32_t CNF10  :2;  /*!< Portx，端口10 */
        __IOM uint32_t MODE11 :2;  /*!< Portx，端口11 */
        __IOM uint32_t CNF11  :2;  /*!< Portx，端口11 */
        __IOM uint32_t MODE12 :2;  /*!< Portx，端口12 */
        __IOM uint32_t CNF12  :2;  /*!< Portx，端口12 */
        __IOM uint32_t MODE13 :2;  /*!< Portx，端口13 */
        __IOM uint32_t CNF13  :2;  /*!< Portx，端口13 */
        __IOM uint32_t MODE14 :2;  /*!< Portx，端口14 */
        __IOM uint32_t CNF14  :2;  /*!< Portx，端口14 */
        __IOM uint32_t MODE15 :2;  /*!< Portx，端口15 */
        __IOM uint32_t CNF15  :2;  /*!< Portx，端口15 */
    };
    __IOM uint32_t reg;
}UN_GPIO_CRH;

#define GPIO_CRX_MODE_INPUT         0   /*!< 输入模式，一般用于ADC，或者低功耗下省电 */
#define GPIO_CRX_MODE_OUTPUT_10M    1   /*!< 输出模式，最大速度10MHz */
#define GPIO_CRX_MODE_OUTPUT_2M     2   /*!< 输出模式，最大速度2MHz */
#define GPIO_CRX_MODE_OUTPUT_50M    3   /*!< 输出模式，最大速度50MHz */

#define GPIO_CRC_CNF_INPUT_ANALOG   0   /*!< Analog mode 模拟输入模式，用于ADC场景 */
#define GPIO_CRC_CNF_INPUT_FLOATING 1   /*!< Floating input (reset state) 浮空输入模式(复位后的状态) */
#define GPIO_CRC_CNF_INPUT_PULL     2   /*!< Input with pull-up / pull-down 上拉/下拉输入模式 */

#define GPIO_CRC_CNF_OUPUT_PP       0   /*!< General purpose output push-pull 推挽输出模式 */
#define GPIO_CRC_CNF_OUPUT_OD       1   /*!< General purpose output Open-drain 开漏输出模式 */
#define GPIO_CRC_CNF_OUPUT_AF_PP    2   /*!< Alternate Function Push Pull Mode 复用功能推挽输出模式 */
#define GPIO_CRC_CNF_OUPUT_AF_OD    3   /*!< Alternate Function Open Drain Mode 复用功能开漏输出模式 */

/** 
  * @brief 端口输入数据寄存器(GPIOx_IDR) (x=A..E)，只读寄存器
  * @note 偏移地址： 0x08  复位值： 0x0000 XXXX
  * @note 该寄存器只能以WORD为单位读取
  */
typedef union {
    struct {
        __IM uint32_t IDR16  :16;    /*< 输入模式下使用，GPIO的输入状态，0=输入低电平 1=输入高电平 */
             uint32_t RSV    :16;
    };
    __IM uint32_t reg;
}UN_GPIO_IDR;

/** 
  * @brief 端口输出数据寄存器(GPIOx_ODR) (x=A..E)
  * @note 偏移地址： 0x0C  复位值： 0x0000 0000
  * @note 该寄存器只能以WORD为单位读取
  */
typedef union {
    struct {
        __IOM uint32_t ODR16 :16;    /*< 输出模式下使用，0=输出低电平 1=输出高电平 */
              uint32_t RSV   :16;
    };
    __IO uint32_t reg;
}UN_GPIO_ODR;

/** 
  * @brief 端口位设置/清除寄存器(GPIOx_BSRR) (x=A..E)，只写
  * @note 偏移地址： 0x10  复位值： 0x0000 0000
  * @note 该寄存器只能以WORD为单位写入
  * @note 以work为单位写入时，无需读-改-写，因为这些寄存器写0是无效的
  */
typedef union {
    struct {
        __OM uint32_t BSy16 :16;    /*!< 写0=无任何效果 1=将指定GPIOx 端口y 置1 */
        __OM uint32_t BRy16 :16;    /*!< 写0=无任何效果 1=将指定GPIOx 端口y 清0 */
    };
    __OM uint32_t reg;
}UN_GPIO_BSRR;

/** 
  * @brief 端口位清除寄存器(GPIOx_BRR) (x=A..E)，只写
  * @note 偏移地址： 0x14  复位值： 0x0000 0000
  * @note 该寄存器只能以WORD为单位写入
  * @note 以work为单位写入时，无需读-改-写，因为这些寄存器写0是无效的
  */
typedef union {
    struct {
        __OM uint32_t BRy16 :16;    /*!< 写0=无任何效果 1=将指定GPIOx 端口y 清0 */
             uint32_t RSV   :16;
    };
    __OM uint32_t reg;
}UN_GPIO_BRR;

/** 
  * @brief 端口配置锁定寄存器(GPIOx_LCKR) (x=A..E)
  * @note 偏移地址： 0x18  复位值： 0x0000 0000
  * @note 当执行正确的写序列设置了位16(LCKK)时，该寄存器用来锁定端口位的配置。
  * @note 每个锁定位锁定控制寄存器(CRL, CRH)中相应的4个位。即MODE[1:0]和CNF[1:0]
  */
typedef union {
    struct {
        __IOM uint32_t LCK0  :1;    /*!< GPIOx 端口0的锁位，这些位可读可写但只能在LCKK位为0时写入。 0：不锁定 1：锁定 */
        __IOM uint32_t LCK1  :1;    /*!< 端口锁位 */
        __IOM uint32_t LCK2  :1;    /*!< 端口锁位 */
        __IOM uint32_t LCK3  :1;    /*!< 端口锁位 */
        __IOM uint32_t LCK4  :1;    /*!< 端口锁位 */
        __IOM uint32_t LCK5  :1;    /*!< 端口锁位 */
        __IOM uint32_t LCK6  :1;    /*!< 端口锁位 */
        __IOM uint32_t LCK7  :1;    /*!< 端口锁位 */
        __IOM uint32_t LCK8  :1;    /*!< 端口锁位 */
        __IOM uint32_t LCK9  :1;    /*!< 端口锁位 */
        __IOM uint32_t LCK10 :1;    /*!< 端口锁位 */
        __IOM uint32_t LCK11 :1;    /*!< 端口锁位 */
        __IOM uint32_t LCK12 :1;    /*!< 端口锁位 */
        __IOM uint32_t LCK13 :1;    /*!< 端口锁位 */
        __IOM uint32_t LCK14 :1;    /*!< 端口锁位 */
        __IOM uint32_t LCK15 :1;    /*!< 端口锁位 */
        __IOM uint32_t LCKK  :1;    /*!< 锁键 (Lock key) 0：端口配置锁键位激活 1：端口配置锁键位被激活，下次系统复位前GPIOx_LCKR寄存器被锁住。
                                         锁键的写入序列： 写1 -> 写0 -> 写1 -> 读0 -> 读1 最后一个读可省略，但可以用来确认锁键已被激活。*/
              uint32_t RSV   :15;
    };
    __IOM uint32_t reg;
}UN_GPIO_LCKR;

/** 
  * @brief 事件控制寄存器(AFIO_EVCR)
  * @note 偏移地址： 0x00  复位值： 0x0000 0000
  */
typedef union {
    struct {
        __IOM uint32_t PIN  :4;     /*!< 引脚选择(x=A…E) (Pin selection)，选择用于输出Cortex的EVENTOUT信号的引脚 */
        __IOM uint32_t PORT :3;     /*!< 端口选择 (Port selection) 000=PA 001=PB 010=PC 011=PD 100=PE */
        __IOM uint32_t EVOE :1;     /*!< 允许事件输出 (Event output enable)，设置该位后， Cortex的EVENTOUT将连接到由PORT[2:0]和PIN[3:0]选定的I/O口 */
        __IOM uint32_t RSV  :24;
    };
    __IOM uint32_t reg;
}UN_AFIO_EVCR;

/** 
  * @brief 复用重映射和调试I/O配置寄存器(AFIO_MAPR)
  * @note 地址偏移： 0x04  复位值： 0x0000 0000
  * @note 非互联型产品，互联型规格定义有所不同
  */
typedef union {
    struct {
        __IOM uint32_t SPI1_REMAP         :1; /*!< SPI1的重映像 */
        __IOM uint32_t I2C1_REMAP         :1; /*!< I2C1的重映像 (I2C1 remapping) */
        __IOM uint32_t USART1_REMAP       :1; /*!< USART1的重映像 (USART1 remapping) */
        __IOM uint32_t USART2_REMAP       :1; /*!< USART2的重映像 (USART2 remapping) */
        __IOM uint32_t USART3_REMAP       :2; /*!< USART3的重映像 (USART3 remapping) */
        __IOM uint32_t TIM1_REMAP         :2; /*!< 定时器1的重映像 (TIM1 remapping) */
        __IOM uint32_t TIM2_REMAP         :2; /*!< 定时器2的重映像 (TIM2 remapping) */
        __IOM uint32_t TIM3_REMAP         :2; /*!< 定时器3的重映像 (TIM3 remapping) */
        __IOM uint32_t TIM4_REMAP         :1; /*!< 定时器4的重映像 (TIM4 remapping) */
        __IOM uint32_t CAN_REMAP          :2; /*!< CAN复用功能重映像 (CAN alternate function remapping) */
        __IOM uint32_t PD01_REMAP         :1; /*!< 端口D0/端口D1映像到OSC_IN/OSC_OUT (Port D0/Port D1 mapping on OSC_IN/OSC_OUT) */
        __IOM uint32_t TIM5CH4_IREMAP     :1; /*!< TIM5通道4内部重映射 (TIM5 channel4 internal remap) */
        __IOM uint32_t ADC1_ETRGINJ_REMAP :1; /*!< ADC1注入转换外部触发重映射 (ADC 1 External trigger injected conversion remapping) */
        __IOM uint32_t ADC1_ETRGREG_REMAP :1; /*!< ADC1规则转换外部触发重映射 (ADC 1 external trigger regular conversion remapping) */
        __IOM uint32_t ADC2_ETRGINJ_REMAP :1; /*!< ADC2注入转换外部触发重映射 (ADC 2 external trigger injected conversion remapping) */
        __IOM uint32_t ADC2_ETRGREG_REMAP :1; /*!< ADC2规则转换外部触发重映射 (ADC 2 external trigger regular conversion remapping) */
              uint32_t RSV1               :3;
        __OM  uint32_t SWJ_CFG            :3; /*!< 串行线JTAG配置 (Serial wire JTAG configuration) */
              uint32_t RSV2               :5;
    };
    __IOM uint32_t reg;
}UN_AFIO_MAPR;

#define HAL_AFIO_REMAP_SWJ_ENABLE     0   /*!< 支持所有调试手段，包括JTAG-DP + SW-DP */
#define HAL_AFIO_REMAP_SWJ_NONJTRST   1   /*!< 支持所有调试手段，包括JTAG-DP + SW-DP，但没有NJTRST */
#define HAL_AFIO_REMAP_SWJ_NOJTAG     2   /*!< 关闭JTAG-DP，启用SW-DP */
#define HAL_AFIO_REMAP_SWJ_DISABLE    3   /*!< 关闭所有调试接口 */
#define HAL_AFIO_REMAP_SWJ_CONFIG(x)  (AFIO->MAPR.SWJ_CFG = (x))

/** 
  * @brief 外部中断配置寄存器 1(AFIO_EXTICR1 / AFIO_EXTICR2 / AFIO_EXTICR3 / AFIO_EXTICR4)
  * @note 地址偏移： 0x08/0x0C/0x10/0x14  复位值： 0x0000 0000
  */
typedef union {
    struct {
        __IOM uint32_t EXTI0 :4;  /*!< EXTIx配置， 这些位可由软件读写，用于选择EXTIx外部中断的输入源   */
        __IOM uint32_t EXTI1 :4;  /*!< EXTIx配置 */
        __IOM uint32_t EXTI2 :4;  /*!< EXTIx配置 */
        __IOM uint32_t EXTI3 :4;  /*!< EXTIx配置 */
              uint32_t RSV   :16;
    };
    __IOM uint32_t reg;
}UN_AFIO_EXTICR;

typedef struct {
  __IOM UN_GPIO_CRL  CRL;   /*!< 端口配置低寄存器(GPIOx_CRL) (x=A..E) */
  __IOM UN_GPIO_CRH  CRH;   /*!< 端口配置高寄存器(GPIOx_CRH) (x=A..E) */
  __IM  UN_GPIO_IDR  IDR;   /*!< 端口输入数据寄存器(GPIOx_IDR) (x=A..E) */
  __IOM UN_GPIO_ODR  ODR;   /*!< 端口输出数据寄存器(GPIOx_ODR) (x=A..E) */
  __OM  UN_GPIO_BSRR BSRR;  /*!< 端口位设置/清除寄存器(GPIOx_BSRR) (x=A..E) */
  __OM  UN_GPIO_BRR  BRR;   /*!< 端口位清除寄存器(GPIOx_BRR) (x=A..E) */
  __IOM UN_GPIO_LCKR LCKR;  /*!< 端口配置锁定寄存器(GPIOx_LCKR) (x=A..E) */
} GPIO_TypeDef;

typedef struct {
  __IOM UN_AFIO_EVCR   EVCR;       /*!< 事件控制寄存器(AFIO_EVCR) */
  __IOM UN_AFIO_MAPR   MAPR;       /*!< 复用重映射和调试I/O配置寄存器(AFIO_MAPR) */
  __IOM UN_AFIO_EXTICR EXTICR[4];  /*!< 外部中断配置寄存器 1(AFIO_EXTICR1~4) */
        uint32_t       RESERVED0;
  __IOM uint32_t       MAPR2;      /*!< 未使用 */
} AFIO_TypeDef;

#define AFIO    ((AFIO_TypeDef *)AFIO_BASE)     /*!< 0x4001 0000 - 0x4001 03FF */
#define GPIOA   ((GPIO_TypeDef *)GPIOA_BASE)    /*!< 0x4001 0800 - 0x4001 0BFF */
#define GPIOB   ((GPIO_TypeDef *)GPIOB_BASE)    /*!< 0X4001 0C00 - 0x4001 0FFF */
#define GPIOC   ((GPIO_TypeDef *)GPIOC_BASE)    /*!< 0x4001 1000 - 0x4001 13FF */
#define GPIOD   ((GPIO_TypeDef *)GPIOD_BASE)    /*!< 0x4001 1400 - 0x4001 17FF */
#define GPIOE   ((GPIO_TypeDef *)GPIOE_BASE)    /*!< 0x4001 1800 - 0x4001 1BFF */
// #define GPIOF   ((GPIO_TypeDef *)GPIOE_BASE)    /*!< 0x4001 2000 - 0x4001 23FF */
// #define GPIOG   ((GPIO_TypeDef *)GPIOE_BASE)    /*!< 0x4001 2000 - 0x4001 23FF */

#endif